package com.cloud.clouduser.security.config;

import com.cloud.clouduser.security.base.SecurityPorperties;
import com.cloud.clouduser.security.base.code.imagecode.CommonImageCodeGenerator;
import com.cloud.clouduser.security.base.code.imagecode.ImageCodeGenerator;
import com.cloud.clouduser.security.common.filters.CommonImageCodeValidateFilter;
import com.cloud.clouduser.security.common.resulthandler.CommonAuthenticationFailureHandler;
import com.cloud.clouduser.security.common.resulthandler.CommonAuthenticationSuccessHandler;
import com.cloud.clouduser.security.wareable.WareAbleUserDetailsService;
import com.netflix.discovery.converters.Auto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @Aurher: QiaoHang
 * @Description:
 * @Data: 2019/9/23 9:07
 * @Modified By:
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * This component will be need by UsernamePasswordAuthenticationFilter.
     */
    @Autowired
    WareAbleUserDetailsService userDetailsService;

    /**
     * This component will be invoke when userdetails is authenticaed successfunlly.
     */
    @Autowired
    CommonAuthenticationSuccessHandler commonAuthenticationSuccessHandler;

    /**
     * This component will be invoke when userdetails is authenticaed failurely.
     */
    @Autowired
    CommonAuthenticationFailureHandler commonAuthenticationFailureHandler;

    /**
     * This component will be invoke when some RequestMapping need check validateCode.
     */
    @Autowired
    CommonImageCodeValidateFilter commonImageCodeValidateFilter;

    /**
     * This component support you Some active properties，
     * will helping runing a prefer freamwork which defiend by yourself.
     */
    @Autowired
    SecurityPorperties securityProperties;

    /**
     * This componet support you one type of passwordEncoder，
     * to keeping login info safety.
     */
    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    /**
     * This configure support you init some definenation conponent ，
     * which can keepping affect Security as your logic.
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    /**
     * This configure support you some web conbfigureation ,
     * such as ignore some static resoureces ,
     * such as setApplicationContext.
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().mvcMatchers("/resources/**");
    }

    /**
     * This configure is the path of Security ,
     * security read this configure to deal some safty authentication which defined by yourself,
     * notice : 1.csrf.
     *          2.release your ahthentication url.
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(commonImageCodeValidateFilter, UsernamePasswordAuthenticationFilter.class)
                .csrf().disable()
                .formLogin()
                //登录页自定义一个controller-url，在url上根据请求类型做不同的跳转，同时满足form 和 restFul 风格的请求！
                .loginPage("/authentication/required")
                //自定义表单提交/restFul提交请求验证的url(默认未/login)
                .loginProcessingUrl("/authentication/form")
                //登录认证成功后的调度
                .successHandler(commonAuthenticationSuccessHandler)
                //登录失败的调度
                .failureHandler(commonAuthenticationFailureHandler)
                .and()
                .authorizeRequests()    // 定义哪些URL需要被保护、哪些不需要被保护
                .antMatchers("/authentication/required",
                        securityProperties.getBrowser().getLoginPage(),
                        "/authentication/form",
                        "/code/generator/imageCode.do",
                        "/authentication/error").permitAll()
                .anyRequest()           // 任何请求,登录后可以访问
                .authenticated();
    }

    /**
     * 自定义 ImageCodeGenerator 图像生成的组件
     * 当用户没有用实现自己的图像生成组件时起作用
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(value = {ImageCodeGenerator.class})
    public ImageCodeGenerator initDefaultGenerator(){
        return new CommonImageCodeGenerator();
    }

}
